PHPアプリケーションのセッション管理にAWS ElastiCacheを使う
こんにちは。望月です。 AWS上でシステムを構築する上で、「AWSのお作法に従う」のは印象以上に重要です。お作法に関しては色々とあるのですが、 *1その中でも一番大きいのは「サーバーは故障するものという前提で設計する」ことにあると思います。例えば、以下の様な点です。
- WebサーバやAPサーバなどはロードバランサを介して冗長化し、単一障害点ではなくす
- 保管する必要のあるデータは全てS3に保管するか、EBSスナップショットを取得する等のバックアップを実施する
- DBはRDSをできるだけ利用することで、Multi-AZによる障害時自動フェイルオーバーによるサービス継続を実施する
上記1番目の「Web/APサーバの冗長化」ですが、オンプレミスからの移行の際にはこれへの対応が結構大変だったりします。例えば、アプリケーションからローカルのファイルを読み書きするような処理が入っている場合、そのファイルを両方のサーバから読み書きするためにNFS等を利用する必要があります。また、HTTPセッションは各サーバ毎に管理されるため、複数台のAPサーバでそれぞれセッションを管理していたら大変なことになります。サーバ1に初回アクセスしてログインしたユーザが次にサーバ2にアクセスした場合、サーバ2ではセッションを持っていないため不正なアクセスとなってしまいます。
ELBだけではなく一般的なロードバランサは、アクセスされたHTTP内のCookieを見て、特定のクライアントからのアクセスは常に同じサーバに返すSticky Session と呼ばれる仕組みが用意されています。ですが、例えばサーバ1が不調によりdownした場合、常にサーバ1にアクセスしていたユーザは改めてサーバ2に振り分け直されるわけですが、その際にサーバ2にはCookieが存在しないため、これまた不正なアクセスとなってしまいます。Sticky Sessionは悪くはない選択肢ですが、そういった障害の可能性があることは認識しておかないといけません。
では、どうするのがベターでしょうか?MySQLなどのDBでセッション情報を管理するのが良いと思います。PHPの場合、KVSであるmemcachedをネイティブセッションハンドラとして利用することが可能です。
前置きが長くなりましたが、今回はAWS ElastiCacheが提供するMemcachedを利用して、PHPのセッションを管理する方法をまとめます。
ElastiCacheの構築
まず、AWS Management ConsoleのElastiCacheホームにアクセスしましょう。
画面中央の[Get Start Now]をクリックすると、ElastiCacheの作成ウィザードが起動されます。
上の画像で赤く囲った部分が重要です。Nameは、まあいいかと思います。[Engine]でmemcachedを選択して下さい。ElastiCacheでは、memcachedの他にRedisを利用することも出来ます。[Number of Nodes]では、ElastiCacheで起動するノード数を指定します。ElastiCacheはクラスタ構成を組むことができるようになっており、各ノード間のデータはElastiCacheによりレプリケーションされます *2。そのため、このノードの数を増やせば対障害性を向上させたり、パフォーマンス向上のためのスケールアウトを実行することができます。
次の画面ではSecurityGroupとParameter Groupの設定を行います。ここの感覚はRDSとほとんど変わりません。後から変更することも可能です。ここで設定するSecurityGroupには、WebサーバからのTCP 11211番ポートへのアクセスを許すエントリが必要です。
最後に確認画面が表示されるので、そのまま先に進むと作成が開始されます。
この画面に表示されている[Node Endpoint]を、PHP側に設定するので控えておきましょう。
PHP側の設定
Amazon Linuxを2台用意し、両方にPHPをインストールします。
$ sudo yum install httpd24 php55
また、memcachedを利用するためのpeclモジュールが必要なので、それもyumでインストールします。
$ sudo yum install php55-pecl-memcached
次に、PHPのセッション管理の設定を変更します。通常であれば/etc/php.iniに記載されるsession.save_handlerとsession.save_pathを編集しますが、Amazon Linuxのhttpd24パッケージではセッションの設定を/etc/httpd/conf.d/php-55.confのphp_valueを利用して上書きしています。最初この設定が存在していることに気づかず、少しはまりました。変更点は以下の通りです。
11/28 17:28追記 : 一部記述に間違えがあったので修正しました。
$ diff -u /etc/httpd/conf.d/php-5.5.conf.org /etc/httpd/conf.d/php-5.5.conf --- /etc/httpd/conf.d/php-5.5.conf.org 2014-05-15 09:06:22.403837050 +0000 +++ /etc/httpd/conf.d/php-5.5.conf 2014-05-15 09:06:03.956428401 +0000 @@ -28,5 +28,8 @@ # Apache specific PHP configuration options # those can be override in each configured vhost # -php_value session.save_handler "files" -php_value session.save_path "/var/lib/php/5.5/session" +# php_value session.save_handler "files" +# php_value session.save_path "/var/lib/php/5.5/session" + +php_value session.save_handler "memcached" +php_value session.save_path "php-session.xxxxxxx.0001.apne1.cache.amazonaws.com:11211"
confの変更後は、apacheの再起動を行いましょう。
確認
さて、それではPHPで動作確認してみます。以下のようなコードを用意しました。
<?php session_start(); echo "This is Web Server 1<br/>"; if (isset($_SESSION["username"])) { echo $_SESSION["username"]; } else { $_SESSION["username"] = "mochizuki01"; }
上に用意したのが一台目のサーバに用意したPHPスクリプトです。2台目のサーバには"Server2"と表示され、セッションに"mochizuki02"と設定されます。つまり、
- 初回アクセスしたのがServer1なら、次回アクセス以降は[mochizuki01]と表示される。
- 初回アクセスしたのがServer2なら、次回アクセス以降は[mochizuki02]と表示される。
という結果が想定されます。さて、試してみましょう。まず初回アクセスしてみましょう。
Server2へのアクセスとなりました。ということは、セッション共有されていれば、WebServer1にアクセスした時にも[mochizuki02]と表示されるはずです。何度かリロードしてみます。
想定通り、Server1と2でセッションが共有されていることが確認できました。
まとめ
memcachedを利用して、セッションを共有する方法について紹介しました。紹介したとおり、PHPはセッションの保存先をコードを変更することなく切り替えることが出来ます。 *3memcachedの構築も、AWSならボタン操作だけで、すぐに可能です。AWSでPHPアプリケーションを構築する際には、ぜひこの組み合わせを利用してみてください。
参考資料
脚注
- 詳しく知りたい方はCloud Design Patternを参照して下さい。また、弊社の過去ブログでもAWSでのベストプラクティスを多数紹介しています。 ↩
- 調査したところ、ElastiCache for memcachedではレプリケーション機能は提供されていませんでした ↩
- PHPのウェブアプリケーションフレームワーク(WAF)を利用している場合にはWAF固有の設定を行う必要がある場合があるので、各WAFのドキュメントを読んでみてください ↩